package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.result.Result;
import com.sky.service.ReportService;
import com.sky.vo.*;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class ReportServiceImpl implements ReportService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private UserMapper userMapper;

    @Override
    public Result turnoverStatistics(LocalDate begin, LocalDate end) {
        //创建营业额报告视图容器
        TurnoverReportVO reportVO = new TurnoverReportVO();
        //创建日期列表
        List<LocalDate> dateList = new ArrayList<>();
        //创建营业额列表
        List<Double> amountList = new ArrayList<>();
        // 当开始日期不晚于结束日期时执行循环
        while (!begin.isAfter(end)) {
            //1. 把日期添加到dateList里
            dateList.add(begin);
            //2. 查询这一天的营业额，添加到amountList里
            // 获取当天开始时间
            LocalDateTime start = LocalDateTime.of(begin, LocalTime.MIN);
            // 获取当天结束时间
            LocalDateTime stop = LocalDateTime.of(begin, LocalTime.MAX);
            // 查询指定日期范围内的订单总金额
            Double amount = orderMapper.sumAmountByDate(start, stop);
            // 若营业额为空，则设为0
            amount = amount == null ? 0D : amount;
            // 将营业额添加到营业额列表
            amountList.add(amount);
            //到下一天
            begin = begin.plusDays(1);
        }
        //dateList 日期，以逗号分隔，例如：2022-10-01,2022-10-02,2022-10-03
        String dateListStr = dateList.stream()
                .map(localDate -> localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                .collect(Collectors.joining(","));// 将日期列表转换为逗号分隔的字符串形式
        // 设置营业额报告视图对象的日期列表
        reportVO.setDateList(dateListStr);
        //turnoverList  营业额，以逗号分隔，例如：406.0,1520.0,75.0
        String amountListStr = amountList.stream()
                .map(Objects::toString)// 将营业额列表转换为逗号分隔的字符串形式
                .collect(Collectors.joining(","));
        // 设置营业额报告视图对象的营业额列表
        reportVO.setTurnoverList(amountListStr);
        // 返回成功结果，包含营业额报告视图对象
        return Result.success(reportVO);
    }

    @Override
    public Result userStatistics(LocalDate begin, LocalDate end) {
        //创建用户统计报告视图
        UserReportVO reportVO = new UserReportVO();
        //创建日期列表
        List<LocalDate> dateList = new ArrayList<>();
        //创建当天新增用户列表
        List<Integer> newCountList = new ArrayList<>();
        //创建总用户数量列表
        List<Integer> totalCountList = new ArrayList<>();
        //当开始日期不晚于结束日期时执行
        while (!begin.isAfter(end)) {
            //1.把日期加到dateList里面
            dateList.add(begin);

            //2.获取当天的新用户数量
            //2.1获取当前开始时间
            LocalDateTime start = LocalDateTime.of(begin, LocalTime.MIN);
            //2.2获取当前结束时间
            LocalDateTime stop = LocalDateTime.of(begin, LocalTime.MAX);
            //2.3.获取截止到当天的用户总量
            Integer newCount = userMapper.countByDate(start, stop);


            //2.4添加到当天新增用户列表
            newCountList.add(newCount == null ? 0 : newCount);
            //3.获取总用户数量
            Integer totalCount = userMapper.countByDate(start, stop);
            //3.1添加到总用户数量列表
            totalCountList.add(totalCount == null ? 0 : totalCount);
            begin = begin.plusDays(1);

        }

        //日期，以逗号分隔
        String dateListStr = dateList.stream()
                .map(localDate -> localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                .collect(Collectors.joining(","));
        //封装
        reportVO.setDateList(dateListStr);
        //新增用户，以逗号分隔
        String newCountStr = newCountList.stream()
                .map(Objects::toString)
                .collect(Collectors.joining(","));
        //封装
        reportVO.setNewUserList(newCountStr);
        //用户总数量，以逗号分隔
        String totalCountStr = totalCountList.stream()
                .map(Objects::toString)
                .collect(Collectors.joining(","));
        //封装
        reportVO.setTotalUserList(totalCountStr);
        //返回
        return Result.success(reportVO);
    }

    @Override
    public Result ordersStatistics(LocalDate begin, LocalDate end) {
        OrderReportVO reportVO = new OrderReportVO();
        List<LocalDate> dateList = new ArrayList<>();
        List<Integer> countList = new ArrayList<>();
        List<Integer> completeCountList = new ArrayList<>();
        //订单总数
        Integer totalOrderCount = 0;
        //有效订单
        Integer validOrderCount = 0;
        while (!begin.isAfter(end)) {
            dateList.add(begin);
            //统计当天的订单数量
            LocalDateTime start = LocalDateTime.of(begin, LocalTime.MIN);
            LocalDateTime stop = LocalDateTime.of(begin, LocalTime.MAX);
            Integer count = orderMapper.countStatistics(start, stop, null);
            countList.add(count == null ? 0 : count);
            //统计当天的有效订单数量
            Integer completeCount = orderMapper.countStatistics(start, stop, Orders.COMPLETED);
            completeCountList.add(completeCount == null ? 0 : completeCount);
            //订单总数自增
            totalOrderCount += count;
            //有效自增
            validOrderCount += completeCount;
            //到下一天
            begin = begin.plusDays(1);
        }
        //日期，以逗号分隔，例如：2022-10-01,2022-10-02,2022-10-03
        reportVO.setDateList(StringUtils.collectionToCommaDelimitedString(dateList));
        //每日订单数，以逗号分隔，例如：260,210,215
        reportVO.setOrderCountList(StringUtils.collectionToCommaDelimitedString(countList));
        //每日有效订单数，以逗号分隔，例如：20,21,10
        reportVO.setValidOrderCountList(StringUtils.collectionToCommaDelimitedString(completeCountList));
        //订单总数
        reportVO.setTotalOrderCount(totalOrderCount);
        //有效订单数
        reportVO.setValidOrderCount(validOrderCount);
        //订单完成率
        reportVO.setOrderCompletionRate(1.0 * validOrderCount / totalOrderCount);
        return Result.success(reportVO);
    }

    @Override
    public Result top10Dishes(LocalDate begin, LocalDate end) {
        SalesTop10ReportVO reportVO = new SalesTop10ReportVO();
        LocalDateTime start = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime stop = LocalDateTime.of(end, LocalTime.MAX);

        List<GoodsSalesDTO> salesTop10 = orderMapper.salesTop10(start, stop);

        //商品名称列表，以逗号分隔，例如：鱼香肉丝,宫保鸡丁,水煮鱼
        reportVO.setNameList(salesTop10.stream().map(GoodsSalesDTO::getName).collect(Collectors.joining(",")));
        //销量列表，以逗号分隔，例如：260,215,200
        reportVO.setNumberList(salesTop10.stream().map(goodsSalesDTO -> goodsSalesDTO.getNumber().toString()).collect(Collectors.joining(",")));
        return Result.success(reportVO);
    }

    @Override
    public void export(HttpServletResponse response) throws IOException {
        //1.读取Excel模板文件
        InputStream is = this.getClass().getClassLoader().getResourceAsStream("templates/yunYIng.xlsx");
        XSSFWorkbook workbook = new XSSFWorkbook(is); //创建一个新的Excel工作薄对象
        XSSFSheet sheet = workbook.getSheetAt(0); //获取工作薄中的第一个工作表

        //2.概览数据
        LocalDate today = LocalDate.now(); //获取当前日期
        LocalDate startDay = today.minusDays(30); //获取30天前的日期
        LocalDate yesterday = today.minusDays(1); //获取昨天的日期

        //2.1设置标题
        sheet.getRow(1).getCell(1).setCellValue(startDay + "至" + yesterday);
        //2.2 查询近30天的数据
        BusinessDataVO vo = queryBusinessDateByDate(startDay, yesterday);
        //2.3把数据输出到xlsx文件里
        //营业额
        sheet.getRow(3).getCell(2).setCellValue(vo.getTurnover()); //在表格中填入营业额数据
        //订单完成率
        sheet.getRow(3).getCell(4).setCellValue(vo.getOrderCompletionRate()*100 + "%"); //在表格中填入订单完成率
        //新增用户数
        sheet.getRow(3).getCell(6).setCellValue(vo.getNewUsers());
        //有效订单
        sheet.getRow(4).getCell(2).setCellValue(vo.getValidOrderCount());
        //平均客单价
        sheet.getRow(4).getCell(4).setCellValue(vo.getUnitPrice());

        //3.明细数据
        int rowNum = 7;
        while (!startDay.isAfter(yesterday)){ //循环-30天前直到昨天
            //3.1 查询当天的数据
            vo = queryBusinessDateByDate(startDay,startDay); //查询当天的数据
            //3.2保存到Excel表格里
            XSSFRow row = sheet.getRow(rowNum); //获取当前行(前边设置的第七行 方便自增)对象
            row.getCell(1).setCellValue(startDay.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); //在表格中填入日期数据
            row.getCell(2).setCellValue(vo.getTurnover()); //在表格中填入营业额数据
            row.getCell(3).setCellValue(vo.getValidOrderCount()); //在表格中填入有效订单
            row.getCell(4).setCellValue(vo.getOrderCompletionRate()*100 + "%"); //在表格中填入订单完成率
            row.getCell(5).setCellValue(vo.getUnitPrice()); //在表格中填入平均可客单价
            row.getCell(6).setCellValue(vo.getNewUsers()); //在表格中填入平均可客单价

            rowNum++; //行自增
            startDay = startDay.plusDays(1); //日期递增一天
        }
        //4. 把Excel导出到客户端
        workbook.write(response.getOutputStream()); //将工作薄 写入到 HttpServletResponse 的输出流中,实现导出
        workbook.close(); //关闭流
    }

    private BusinessDataVO queryBusinessDateByDate(LocalDate begin, LocalDate end) {
        BusinessDataVO vo = new BusinessDataVO(); //创建业务数据对象
        LocalDateTime start = LocalDateTime.of(begin, LocalTime.MIN); //获取开始日期的当天零点时间
        LocalDateTime stop = LocalDateTime.of(end, LocalTime.MAX); //获取结束日期的当天23.59.59时间

        //1.营业额
        Double turnover = orderMapper.sumAmountByDate(start, stop); //查询指定日期范围内的营业额
        vo.setTurnover(turnover == null ? 0 : turnover); //设置营业额到业务数据对象里

        //2.有效订单
        Integer completeCount = orderMapper.countStatistics(start, stop, Orders.COMPLETED); //查询指定日期范围内的有效订单
        vo.setValidOrderCount(completeCount);

        //3.订单完成率
        Integer totalCount = orderMapper.countStatistics(start, stop, null);
        double rate = 0D;
        if (totalCount != null) {
            rate = 1.0 * completeCount / totalCount; //计算订单完成率
        }
        vo.setOrderCompletionRate(rate); //设置订单完成率到业务数据对象中

        //4.平均客单价
        Double priceAvg = 0D;
        if (completeCount != 0) {
            priceAvg = 1.0 * turnover / completeCount; //计算平均客单价
        }
        vo.setUnitPrice(priceAvg);

        //5.新增用户数
        Integer newUserCount = userMapper.countByDate(start,stop); //查询指定日期范围内的新增用户数量
        vo.setNewUsers(newUserCount); //设置新增用户数据到业务对象中
        return vo;
    }
}
